/*
*************************************************************************
*                             包含的头文件
*************************************************************************
*/
#include <rtthread.h>
#include <rthw.h>


#ifndef RT_USING_SMP
extern volatile rt_uint8_t rt_interrupt_nest;
static rt_int16_t rt_scheduler_lock_nest;
struct rt_thread *rt_current_thread;
rt_uint8_t rt_current_priority;
#endif /*RT_USING_SMP*/



/*
*************************************************************************
*                                 全局变量
*************************************************************************
*/
/* 线程控制块指针，用于指向当前线程 */
struct rt_thread *rt_current_thread;

/* 线程就绪列表 */
rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];

/* 线程就绪优先级组 */
rt_uint32_t rt_thread_ready_priority_group;

/* 当前优先级 */
rt_uint8_t rt_current_priority;

/* 线程删除列表 */
rt_list_t rt_thread_defunct;

/* 空闲进程 */
extern struct rt_thread idle;


/*
*************************************************************************
*                               函数实现
*************************************************************************
*/

/* 初始化系统调度器 */
void rt_system_scheduler_init(void)
{	
	register rt_base_t offset;

#ifndef RT_USING_SMP
    rt_scheduler_lock_nest = 0;
#endif /*RT_USING_SMP*/
	
	/* 线程就绪列表初始化 */
	for (offset = 0; offset < RT_THREAD_PRIORITY_MAX; offset ++)
	{
			rt_list_init(&rt_thread_priority_table[offset]);
	}
    
    /* 初始化当前优先级为空闲线程的优先级 */
    rt_current_priority = RT_THREAD_PRIORITY_MAX - 1;
	
	/* 初始化当前线程控制块指针 */
	rt_current_thread = RT_NULL;
    
    /* 初始化线程就绪优先级组 */
    rt_thread_ready_priority_group = 0;
	
}


/* 启动系统调度器 */
void rt_system_scheduler_start(void)
{
	register struct rt_thread *to_thread;
    register rt_ubase_t highest_ready_priority;
    
    /* 获取就绪的最高优先级 */
    highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
    
    /* 获取将要运行线程的线程控制块 */
    to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
                              struct rt_thread,
                              tlist);
    
     rt_current_thread = to_thread;

    /* 从就绪列表删除，变成运行态 */
     rt_schedule_remove_thread(to_thread);
                              
     rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp);
}


/* 将线程插入就绪列表 */
void rt_schedule_insert_thread(struct rt_thread *thread){
    register rt_base_t temp;
    
    /* 关中断 */
    temp = rt_hw_interrupt_disable();
    
    thread->stat = RT_THREAD_READY;
    
    rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]),
                            &(thread->tlist));
    
    /* 设置线程就绪优先级组中对应的位 */
    rt_thread_ready_priority_group |= thread->number_mask;

    /* 开中断 */
    rt_hw_interrupt_enable(temp);
}

void rt_schedule_remove_thread(struct rt_thread *thread)
{
    register rt_base_t temp;


    /* 关中断 */
    temp = rt_hw_interrupt_disable();
    
    /* 将线程从就绪列表删除 */
    rt_list_remove(&(thread->tlist));
    
    if (rt_list_isempty(&(rt_thread_priority_table[thread->current_priority])))
    {
        rt_thread_ready_priority_group &= ~thread->number_mask;
    }

    /* 开中断 */
    rt_hw_interrupt_enable(temp);
}

/* 系统调度 */
// void rt_schedule(void)
// {
//     rt_base_t level;
//     register rt_ubase_t highest_ready_priority;
// 	struct rt_thread *to_thread;
// 	struct rt_thread *from_thread;
	
// 	/* 关中断 */
//     level = rt_hw_interrupt_disable();
    
//     /* 获取就绪的最高优先级 */
//     highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;
    
//     /* 获取就绪的最高优先级对应的线程控制块 */
//     to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
//                               struct rt_thread,
//                               tlist);
	
//     /* 如果目标线程不是当前线程，则要进行线程切换 */
//     if(to_thread != rt_current_thread){
//         rt_current_priority = (rt_uint8_t)highest_ready_priority;
//         from_thread = rt_current_thread;
//         rt_current_thread = to_thread;
        
//         /* 产生上下文切换 */
//         rt_hw_context_switch((rt_uint32_t)&from_thread->sp, (rt_uint32_t)&to_thread->sp);
        
//         rt_hw_interrupt_enable(level);
//     }else{
//         rt_hw_interrupt_enable(level);
//     }
// }


void rt_schedule(void)
{
    rt_base_t level;
    register rt_ubase_t highest_ready_priority;
	struct rt_thread *to_thread;
	struct rt_thread *from_thread;
	
	/* 关中断 */
    level = rt_hw_interrupt_disable();

    if (rt_scheduler_lock_nest == 0){
        int need_insert_from_thread = 0;
    
        /* 获取就绪的最高优先级 */
        highest_ready_priority = __rt_ffs(rt_thread_ready_priority_group) - 1;

        /* 获取就绪的最高优先级对应的线程控制块 */
        to_thread = rt_list_entry(rt_thread_priority_table[highest_ready_priority].next,
                                    struct rt_thread,
                                    tlist);

        if ((rt_current_thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY){
            if (rt_current_thread->current_priority < highest_ready_priority){
                /* 当前线程优先级最高，执行到这里表示发生错误？ */
                to_thread = rt_current_thread;
            }else{
                need_insert_from_thread = 1;
            }
        }

        /* 如果目标线程不是当前线程，则要进行线程切换 */
        if(to_thread != rt_current_thread){
            rt_current_priority = (rt_uint8_t)highest_ready_priority;
            from_thread = rt_current_thread;
            rt_current_thread = to_thread;

            if(need_insert_from_thread){
                rt_schedule_insert_thread(from_thread);
            }

            /* 从就绪列表中移除 */
            rt_schedule_remove_thread(to_thread);

            /* 中断计数器 */
            if(rt_interrupt_nest == 0){
                extern void rt_thread_handle_sig(rt_bool_t clean_state);
            
                /* 产生上下文切换 */
                rt_hw_context_switch((rt_uint32_t)&from_thread->sp, (rt_uint32_t)&to_thread->sp);
                
                rt_hw_interrupt_enable(level);

#ifdef RT_USING_SIGNALS
                /* check signal status */
                rt_thread_handle_sig(RT_TRUE);
#endif

                return;
            }else{
                // printf("rt_interrupt_nest: %d\r\n", rt_interrupt_nest);
                // printf("rt_thread_switch_interrupt_flag: %d\r\n", get_rt_thread_switch_interrupt_flag());
                // printf("from: %s to: %s\r\n", from_thread->name, to_thread->name);

                rt_hw_context_switch_interrupt((rt_ubase_t)&from_thread->sp,
                            (rt_ubase_t)&to_thread->sp);
            }
        }else{
            /* 从就绪列表中移除 */
            rt_schedule_remove_thread(rt_current_thread);
        }
    }

    rt_hw_interrupt_enable(level);
}

#ifndef RT_USING_SMP
void rt_enter_critical(void)
{
    register rt_base_t level;

    /* disable interrupt */
    level = rt_hw_interrupt_disable();

    /*
     * the maximal number of nest is RT_UINT16_MAX, which is big
     * enough and does not check here
     */
    rt_scheduler_lock_nest ++;

    /* enable interrupt */
    rt_hw_interrupt_enable(level);
}

void rt_exit_critical(void)
{
    register rt_base_t level;

    /* disable interrupt */
    level = rt_hw_interrupt_disable();

    rt_scheduler_lock_nest --;

    if (rt_scheduler_lock_nest <= 0)
    {
        rt_scheduler_lock_nest = 0;
        /* enable interrupt */
        rt_hw_interrupt_enable(level);

        rt_schedule();
    }
    else
    {
        /* enable interrupt */
        rt_hw_interrupt_enable(level);
    }
}

#endif /*RT_USING_SMP*/

